# -*- coding: utf-8 -*-
"""
Markdown 和 HTML 格式互转工具类
支持 Markdown 转 HTML 和 HTML 转 Markdown
"""
import re
import html
from typing import Optional, Dict, Any
from urllib.parse import unquote


class MarkdownConverter:
    """Markdown 和 HTML 格式互转工具类"""
    
    def __init__(self):
        # HTML 标签到 Markdown 的映射
        self.html_to_md_map = {
            'h1': '# ',
            'h2': '## ',
            'h3': '### ',
            'h4': '#### ',
            'h5': '##### ',
            'h6': '###### ',
            'strong': '**',
            'b': '**',
            'em': '*',
            'i': '*',
            'code': '`',
            'pre': '```\n',
            'blockquote': '> ',
            'ul': '- ',
            'ol': '1. ',
            'li': '- ',
            'hr': '---',
            'br': '\n',
            'p': '\n\n'
        }
        
        # Markdown 语法正则表达式
        self.md_patterns = {
            'headers': r'^(#{1,6})\s+(.+)$',
            'bold': r'\*\*(.+?)\*\*',
            'italic': r'\*(.+?)\*',
            'code_inline': r'`(.+?)`',
            'code_block': r'```(\w+)?\n(.*?)\n```',
            'links': r'\[([^\]]+)\]\(([^)]+)\)',
            'images': r'!\[([^\]]*)\]\(([^)]+)\)',
            'blockquotes': r'^>\s+(.+)$',
            'lists': r'^[\s]*[-*+]\s+(.+)$',
            'ordered_lists': r'^[\s]*\d+\.\s+(.+)$',
            'hr': r'^[-*_]{3,}$',
            'line_breaks': r'\n\s*\n'
        }
    
    def markdown_to_html(self, markdown_text: str, 
                        extensions: Optional[list] = None,
                        **kwargs) -> str:
        """
        将 Markdown 转换为 HTML
        
        Args:
            markdown_text: Markdown 文本
            extensions: 扩展功能列表
            **kwargs: 其他参数
            
        Returns:
            HTML 文本
        """
        if not markdown_text:
            return ""
        
        # 尝试使用 markdown 库
        try:
            import markdown
            md = markdown.Markdown(extensions=extensions or ['extra', 'codehilite'])
            return md.convert(markdown_text)
        except ImportError:
            # 如果没有 markdown 库，使用自定义转换
            return self._markdown_to_html_custom(markdown_text)
    
    def _markdown_to_html_custom(self, markdown_text: str) -> str:
        """自定义 Markdown 转 HTML 实现"""
        html_text = markdown_text
        
        # 处理标题
        for i in range(6, 0, -1):
            pattern = r'^' + '#' * i + r'\s+(.+)$'
            html_text = re.sub(pattern, rf'<h{i}>\1</h{i}>', html_text, flags=re.MULTILINE)
        
        # 处理粗体
        html_text = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', html_text)
        
        # 处理斜体
        html_text = re.sub(r'\*(.+?)\*', r'<em>\1</em>', html_text)
        
        # 处理行内代码
        html_text = re.sub(r'`(.+?)`', r'<code>\1</code>', html_text)
        
        # 处理代码块
        html_text = re.sub(r'```(\w+)?\n(.*?)\n```', 
                          r'<pre><code class="language-\1">\2</code></pre>', 
                          html_text, flags=re.DOTALL)
        
        # 处理链接
        html_text = re.sub(r'\[([^\]]+)\]\(([^)]+)\)', r'<a href="\2">\1</a>', html_text)
        
        # 处理图片
        html_text = re.sub(r'!\[([^\]]*)\]\(([^)]+)\)', r'<img src="\2" alt="\1">', html_text)
        
        # 处理引用
        html_text = re.sub(r'^>\s+(.+)$', r'<blockquote>\1</blockquote>', html_text, flags=re.MULTILINE)
        
        # 处理无序列表
        html_text = re.sub(r'^[\s]*[-*+]\s+(.+)$', r'<li>\1</li>', html_text, flags=re.MULTILINE)
        
        # 处理有序列表
        html_text = re.sub(r'^[\s]*\d+\.\s+(.+)$', r'<li>\1</li>', html_text, flags=re.MULTILINE)
        
        # 处理分割线
        html_text = re.sub(r'^[-*_]{3,}$', r'<hr>', html_text, flags=re.MULTILINE)
        
        # 处理换行
        html_text = re.sub(r'\n\s*\n', r'</p>\n<p>', html_text)
        html_text = f'<p>{html_text}</p>'
        
        # 包装列表项
        html_text = re.sub(r'(<li>.*?</li>)', r'<ul>\1</ul>', html_text, flags=re.DOTALL)
        
        return html_text
    
    def html_to_markdown(self, html_text: str, 
                        strip_tags: Optional[list] = None,
                        **kwargs) -> str:
        """
        将 HTML 转换为 Markdown
        
        Args:
            html_text: HTML 文本
            strip_tags: 要移除的标签列表
            **kwargs: 其他参数
            
        Returns:
            Markdown 文本
        """
        if not html_text:
            return ""
        
        # 尝试使用 html2text 库
        try:
            import html2text
            h = html2text.HTML2Text()
            h.ignore_links = kwargs.get('ignore_links', False)
            h.ignore_images = kwargs.get('ignore_images', False)
            h.body_width = kwargs.get('body_width', 0)
            return h.handle(html_text)
        except ImportError:
            # 如果没有 html2text 库，使用自定义转换
            return self._html_to_markdown_custom(html_text, strip_tags)
    
    def _html_to_markdown_custom(self, html_text: str, strip_tags: Optional[list] = None) -> str:
        """自定义 HTML 转 Markdown 实现"""
        markdown_text = html_text
        
        # 移除不需要的标签
        if strip_tags:
            for tag in strip_tags:
                markdown_text = re.sub(rf'<{tag}[^>]*>.*?</{tag}>', '', markdown_text, flags=re.DOTALL)
                markdown_text = re.sub(rf'<{tag}[^>]*/?>', '', markdown_text)
        
        # 处理标题
        for i in range(1, 7):
            markdown_text = re.sub(
                rf'<h{i}[^>]*>(.*?)</h{i}>', 
                rf'{"#" * i} \1\n', 
                markdown_text, 
                flags=re.DOTALL
            )
        
        # 处理粗体
        markdown_text = re.sub(r'<(strong|b)[^>]*>(.*?)</(strong|b)>', r'**\2**', markdown_text, flags=re.DOTALL)
        
        # 处理斜体
        markdown_text = re.sub(r'<(em|i)[^>]*>(.*?)</(em|i)>', r'*\2*', markdown_text, flags=re.DOTALL)
        
        # 处理代码
        markdown_text = re.sub(r'<code[^>]*>(.*?)</code>', r'`\1`', markdown_text, flags=re.DOTALL)
        
        # 处理代码块
        markdown_text = re.sub(
            r'<pre[^>]*><code[^>]*>(.*?)</code></pre>', 
            r'```\n\1\n```', 
            markdown_text, 
            flags=re.DOTALL
        )
        
        # 处理链接
        markdown_text = re.sub(
            r'<a[^>]*href=["\']([^"\']*)["\'][^>]*>(.*?)</a>', 
            r'[\2](\1)', 
            markdown_text, 
            flags=re.DOTALL
        )
        
        # 处理图片
        markdown_text = re.sub(
            r'<img[^>]*src=["\']([^"\']*)["\'][^>]*alt=["\']([^"\']*)["\'][^>]*/?>', 
            r'![\2](\1)', 
            markdown_text
        )
        
        # 处理引用
        markdown_text = re.sub(r'<blockquote[^>]*>(.*?)</blockquote>', r'> \1', markdown_text, flags=re.DOTALL)
        
        # 处理列表
        markdown_text = re.sub(r'<li[^>]*>(.*?)</li>', r'- \1', markdown_text, flags=re.DOTALL)
        
        # 处理分割线
        markdown_text = re.sub(r'<hr[^>]*/?>', r'---', markdown_text)
        
        # 处理段落
        markdown_text = re.sub(r'<p[^>]*>(.*?)</p>', r'\1\n\n', markdown_text, flags=re.DOTALL)
        
        # 处理换行
        markdown_text = re.sub(r'<br[^>]*/?>', r'\n', markdown_text)
        
        # 清理多余的空白
        markdown_text = re.sub(r'\n\s*\n\s*\n', r'\n\n', markdown_text)
        markdown_text = markdown_text.strip()
        
        return markdown_text
    
    def sanitize_html(self, html_text: str, allowed_tags: Optional[list] = None) -> str:
        """
        清理 HTML，移除不安全的标签和属性
        
        Args:
            html_text: HTML 文本
            allowed_tags: 允许的标签列表
            
        Returns:
            清理后的 HTML 文本
        """
        if not html_text:
            return ""
        
        # 默认允许的标签
        if allowed_tags is None:
            allowed_tags = [
                'p', 'br', 'strong', 'b', 'em', 'i', 'u', 'code', 'pre',
                'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
                'ul', 'ol', 'li', 'blockquote', 'hr',
                'a', 'img', 'table', 'thead', 'tbody', 'tr', 'td', 'th'
            ]
        
        # 移除不允许的标签
        for tag in ['script', 'style', 'iframe', 'object', 'embed']:
            html_text = re.sub(rf'<{tag}[^>]*>.*?</{tag}>', '', html_text, flags=re.DOTALL | re.IGNORECASE)
            html_text = re.sub(rf'<{tag}[^>]*/?>', '', html_text, flags=re.IGNORECASE)
        
        # 移除危险的属性
        dangerous_attrs = ['onclick', 'onload', 'onerror', 'onmouseover', 'javascript:']
        for attr in dangerous_attrs:
            html_text = re.sub(rf'{attr}=["\'][^"\']*["\']', '', html_text, flags=re.IGNORECASE)
        
        return html_text
    
    def extract_text_from_html(self, html_text: str) -> str:
        """
        从 HTML 中提取纯文本
        
        Args:
            html_text: HTML 文本
            
        Returns:
            纯文本
        """
        if not html_text:
            return ""
        
        # 移除所有 HTML 标签
        text = re.sub(r'<[^>]+>', '', html_text)
        
        # 解码 HTML 实体
        text = html.unescape(text)
        
        # 清理空白字符
        text = re.sub(r'\s+', ' ', text)
        text = text.strip()
        
        return text
    
    def get_markdown_preview(self, markdown_text: str, max_length: int = 200) -> str:
        """
        获取 Markdown 的预览文本（转换为纯文本并截取）
        
        Args:
            markdown_text: Markdown 文本
            max_length: 最大长度
            
        Returns:
            预览文本
        """
        if not markdown_text:
            return ""
        
        # 转换为 HTML
        html_text = self.markdown_to_html(markdown_text)
        
        # 提取纯文本
        text = self.extract_text_from_html(html_text)
        
        # 截取指定长度
        if len(text) > max_length:
            text = text[:max_length] + "..."
        
        return text
    
    def validate_markdown(self, markdown_text: str) -> Dict[str, Any]:
        """
        验证 Markdown 语法
        
        Args:
            markdown_text: Markdown 文本
            
        Returns:
            验证结果字典
        """
        result = {
            'valid': True,
            'errors': [],
            'warnings': [],
            'stats': {}
        }
        
        if not markdown_text:
            return result
        
        # 统计信息
        result['stats'] = {
            'total_lines': len(markdown_text.split('\n')),
            'total_chars': len(markdown_text),
            'headers': len(re.findall(r'^#{1,6}\s+', markdown_text, re.MULTILINE)),
            'links': len(re.findall(r'\[([^\]]+)\]\(([^)]+)\)', markdown_text)),
            'images': len(re.findall(r'!\[([^\]]*)\]\(([^)]+)\)', markdown_text)),
            'code_blocks': len(re.findall(r'```', markdown_text))
        }
        
        # 检查未闭合的代码块
        code_blocks = re.findall(r'```', markdown_text)
        if len(code_blocks) % 2 != 0:
            result['errors'].append('未闭合的代码块')
            result['valid'] = False
        
        # 检查未闭合的链接
        open_brackets = len(re.findall(r'\[', markdown_text))
        close_brackets = len(re.findall(r'\]', markdown_text))
        if open_brackets != close_brackets:
            result['warnings'].append('可能有不匹配的方括号')
        
        # 检查未闭合的括号
        open_parens = len(re.findall(r'\(', markdown_text))
        close_parens = len(re.findall(r'\)', markdown_text))
        if open_parens != close_parens:
            result['warnings'].append('可能有不匹配的圆括号')
        
        return result


# 创建全局实例
markdown_converter = MarkdownConverter()


def markdown_to_html(text: str, **kwargs) -> str:
    """便捷函数：Markdown 转 HTML"""
    return markdown_converter.markdown_to_html(text, **kwargs)


def html_to_markdown(text: str, **kwargs) -> str:
    """便捷函数：HTML 转 Markdown"""
    return markdown_converter.html_to_markdown(text, **kwargs)


def sanitize_html(text: str, **kwargs) -> str:
    """便捷函数：清理 HTML"""
    return markdown_converter.sanitize_html(text, **kwargs)


def extract_text_from_html(text: str) -> str:
    """便捷函数：从 HTML 提取纯文本"""
    return markdown_converter.extract_text_from_html(text)


def get_markdown_preview(text: str, **kwargs) -> str:
    """便捷函数：获取 Markdown 预览"""
    return markdown_converter.get_markdown_preview(text, **kwargs)


def validate_markdown(text: str) -> Dict[str, Any]:
    """便捷函数：验证 Markdown"""
    return markdown_converter.validate_markdown(text) 